﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Logs;

namespace Communication.Udp {
    /// <summary>
    /// 异步Udp
    /// </summary>
    public class AsyncUdpServer {
        public UdpClient client;
        public IPEndPoint ipEndPoint;
        private AsyncUdpProMsg proMsg = new AsyncUdpProMsg();
        private Thread ReceiveThread = null;

        /// <summary>
        /// 本地IP
        /// </summary>
        private string ip;

        /// <summary>
        /// 本地端口
        /// </summary>
        private int listenPort;

        #region 异步状态同步
        /// <summary>
        /// 接收异步状态同步
        /// </summary>
        private ManualResetEvent receiveDone = new ManualResetEvent(false);
        /// <summary>
        /// 发送异步状态同步
        /// </summary>
        private ManualResetEvent sendDone = new ManualResetEvent(false);
        #endregion

        #region 发布数据接收事件
        public event ReceviceMsgEvent receviceMsgEvent;
        #endregion

        #region 构造函数
        public AsyncUdpServer() {
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="listenPort">本地端口</param>
        public AsyncUdpServer(int listenPort) {
            this.listenPort = listenPort;
        }
        #endregion

        #region 启动Udpserver
        /// <summary>
        /// 开启Udp服务
        /// </summary>
        public void StartServer() {
            ipEndPoint = new IPEndPoint(IPAddress.Any, this.listenPort);
            this.client = new UdpClient(ipEndPoint);
            Log.Info(string.Format("启动Udp成功！地址：{0}",ipEndPoint));
        }
#endregion

#region 接收数据
        /// <summary>
        /// 接收数据
        /// </summary>
        public void ReceiveMsg() {
            ReceiveThread = new Thread(() => {
                while (true) {
                    if (!object.ReferenceEquals(Thread.CurrentThread, ReceiveThread)) {
                        break;
                    }
                    try {
                        IAsyncResult iar = client.BeginReceive(new AsyncCallback(ReceiveCallBack), this.client);
                        receiveDone.WaitOne();
                        Thread.Sleep(100);
                    } catch (Exception e) {
                        Log.Error(string.Format("错误：{0}",e.Message));
                    }
                }
            });
            ReceiveThread.IsBackground = true;
            ReceiveThread.Start();
        }

        /// <summary>
        /// 接收回调函数
        /// </summary>
        /// <param name="iar"></param>
        private void ReceiveCallBack(IAsyncResult iar) {
            this.client = iar.AsyncState as UdpClient;
            if (iar.IsCompleted) {
                try {
                    byte[] receivebuff = client.EndReceive(iar, ref ipEndPoint);
                    if (receviceMsgEvent != null) {
                        receviceMsgEvent(ipEndPoint, receivebuff);
                    }

                    SendMsg(ipEndPoint, receivebuff);
                    receiveDone.Set();
                } catch (Exception e) {
                    Log.Error(string.Format("错误：{0}",e.Message));
                }
            }
        }
#endregion

#region 发送数据
        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="address">目标地址</param>
        /// <param name="sendbuff">发送数据</param>
        public void SendMsg(IPEndPoint address, byte[] sendbuff) {
            client.Connect(ipEndPoint);
            client.BeginSend(proMsg.ToSendMsg(), proMsg.ToSendMsg().Length, new AsyncCallback(SendCallBack), client);
            sendDone.WaitOne();
        }

        /// <summary>
        /// 发送回调函数
        /// </summary>
        /// <param name="iar"></param>
        private void SendCallBack(IAsyncResult iar) {
            client = iar.AsyncState as UdpClient;
            client.EndSend(iar);
            sendDone.Set();
        }
#endregion

    }
    public delegate void ReceviceMsgEvent(IPEndPoint ipEndPoint, byte[] msg);
}
